package main

import (
	"fmt"
	"log"
	"net"
	"net/rpc"

	"gitee.com/go-course/go11/skill/rpc/hello/model"
)

func main() {
	// 然后我们建立一个唯一的TCP链接，
	listener, err := net.Listen("tcp", ":1234")
	if err != nil {
		log.Fatal("ListenTCP error:", err)
	}

	// 提前加载业务服务
	// 为你的服务添加一个名称,相当于一个Namespace  <ServiceName>.<FunctionName>
	rpc.RegisterName("HelloService", new(HelloWorldServiceImpl))

	// 通过rpc.ServeConn函数在该TCP链接上为对方提供RPC服务。
	// 没Accept一个请求，就创建一个goroutie进行处理
	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Fatal("Accept error:", err)
		}

		// 前面都是tcp的知识, 到这个RPC就接管了
		// 因此 你可以认为 rpc 帮我们封装消息到函数调用的这个逻辑,
		// 提升了工作效率, 逻辑比较简洁，可以看看他代码
		go rpc.ServeConn(conn)

		// rpc框架怎么知道 来自TCP连接上的用户请求如何处理? 需要加载业务服务
	}
}

// 1 定义业务实现 用于提供业务处理能力的Service对象, 和Impl很像
// 怎么把 这个服务对象 暴露为又给rpc服务
type HelloWorldServiceImpl struct {
}

// 作为一个net/rpc 的一种业务实现, 需要遵循 net/rpc的接口约束
// net/rpc ：FN(request <type>, responese *<type>) error
// 为什么 response要是指针,   client.Hello(request, *response), 通过response对象接受处理结构
// gorm json Unmarshal()
func (i *HelloWorldServiceImpl) Hello(in *model.HelloRequest, out *model.HelloResponse) error {
	// 需要赋值
	out.Value = fmt.Sprintf("Hello, %s", in.Name)
	return nil
}
